﻿Function Load-ProductsManifest
{
        [cmdletbinding()]
        Param( 
        [ValidateScript({Test-Path $_ -PathType Leaf -ErrorAction Stop})] 
        [String] 
        $Path
        )

    Begin
    {
        $watch = [system.diagnostics.stopwatch]::StartNew() 
        write-verbose "Start Load-ProductsManifest from $Path"
    }
    End
    {
        write-verbose "End Load-ProductsManifest from $Path"
        $watch.Stop();
        Write-Verbose "function duration : $($watch.Elapsed)"
    }
    Process 
    {
        #Load product Manifest file
        #$products =@()
        #Select-Xml -Path $Path -XPath "//product" | ForEach-Object {$products += New-ProductManifest -source $_.Node}
        #Write-Output $products
        Select-Xml -Path $Path -XPath "//product" | ForEach-Object {New-ProductManifest -source $_.Node}
    }
}

Function New-ProductManifest
{
        Param( 
        [Parameter(Mandatory=$true,ValueFromPipeline=$true)] 
        [System.Xml.XmlElement] 
        $source
        )

    Begin
    {
        $watch = [system.diagnostics.stopwatch]::StartNew() 
        write-verbose "Start New-ProductManifest from $source"
    }
    End
    {
        write-verbose "End New-ProductManifest from $source"
        $watch.Stop();
        Write-Verbose "function duration : $($watch.Elapsed)"
    }
    Process 
    {

        #Add mandatory properties
        $product = New-Object System.Object
        $product | Add-Member -type NoteProperty -name Id -value $source.id
        $product | Add-Member -type NoteProperty -name Name -value $source.name
        $product | Add-Member -type NoteProperty -name Platform -value $source.platform
        $product | Add-Member -type NoteProperty -name Version -value $source.version
        $product | Add-Member -type NoteProperty -name CheckProvider -value $source.checkProvider
        $product | Add-Member -type NoteProperty -name CheckPath -value $source.checkPath
        $product | Add-Member -type NoteProperty -name InstallProvider $source.installProvider
        $product | Add-Member -type NoteProperty -name Installer $source.installer
        $product | Add-Member -type NoteProperty -name ResponseFile $source.responseFile
        $product | Add-Member -type NoteProperty -name CommandArguments $source.commandArguments
        $product | Add-Member -type NoteProperty -name Action $source.action

        #Add Dynamic properties
        $source.Attributes | ForEach-Object{
            
                Write-Verbose "Add dynamic property $($_.Name) from component tag with Value $($_.Value)"
                $product | Add-Member -type NoteProperty -name $_.Name -value $_.Value -ErrorAction SilentlyContinue
            
        }
        
        Write-Output $product
    }
}


Function Install-Product
{ 
    [cmdletbinding(SupportsShouldProcess=$True)]
    Param( 
        [Parameter(Mandatory=$true,ValueFromPipeline=$true)] 
        [System.Object]
        $ProductManifest
         
    )
    Begin
    {
        $watch = [system.diagnostics.stopwatch]::StartNew() 
        write-verbose "Begin Install-Product $($ProductManifest.id)"
    }
    End
    {
        write-verbose "End Install-Product $($ProductManifest.id)"
        $watch.Stop();
        Write-Verbose "Function duration : $($watch.Elapsed)"
    }
    Process
    {

    }
}

Function Invoke-msi
{ 
    [cmdletbinding(SupportsShouldProcess=$True)]
    Param( 
        [ValidateScript({Test-Path $_ -PathType Container -ErrorAction Stop})] 
        [Parameter(Mandatory=$true,ValueFromPipeline=$true)] 
        [String] 
        $Path,
        
        [Parameter(Mandatory=$true,ValueFromPipeline=$true)] 
        [String] 
        $MSIFileName,

        [Parameter(Mandatory=$true,ValueFromPipeline=$true)] 
        [String] 
        $MSIAction,

        [Parameter(Mandatory=$true,ValueFromPipeline=$true)] 
        [String]
        $Destination,

        [Parameter(Mandatory=$false,ValueFromPipeline=$true)] 
        [String]
        $AdditionalCommandProperties

         
    )
    Begin
    {
        $watch = [system.diagnostics.stopwatch]::StartNew() 
        write-verbose "Begin Invoke-Msi $Path\$MSIFileName to $Destination"
    }
    End
    {
        write-verbose "End Invoke-Msi $Path\$MSIFileName to $Destination"
        $watch.Stop();
        Write-Verbose "Function duration : $($watch.Elapsed)"
    }
    Process
    {
        $msiCommand = "c:\windows\system32\msiexec.exe"

        #$msiAction="/i"
        #if ($ProductManifest.Action -ne 'install')
        #{
        #    $msiAction="/u"            
        #}

        $installerPath = Join-Path -Path $Path -ChildPath $MSIFileName

        #Create Command
        $installDir="INSTALLDIR=$Destination"
         
        #Invoke-Command -ScriptBlock ([scriptblock]::create($commandToExecute))
        if ($msiAction -eq "/u")
        {
            Write-Verbose "Invoke msi for uninstall"
            $arguments= @("/qn", $msiAction, $installerPath)
            $commandToExecute = [System.String]::Format("{0} /qn {1} {2}",$msiCommand, $msiAction, $installerPath)
        }
        else
        {
            Write-Verbose "Invoke msi for install"
            $arguments= @("/qn", $msiAction, $installerPath, $installDir, $AdditionalCommandProperties)
            $commandToExecute = [System.String]::Format("{0} /qn {1} {2} {3} {4}",$msiCommand, $msiAction, $installerPath, $installDir, $AdditionalCommandProperties)
        }

        Write-Verbose "MSI command to execute is : $commandToExecute"

        if ($PSBoundParameters['WhatIf'] -eq $True)
        {
            Write-Host $commandToExecute
        }
        else
        {


            $process = Start-Process -FilePath $msiCommand -ArgumentList $arguments -Wait -PassThru -WindowStyle Hidden

            if ($process.ExitCode -ne 0)
            {
                throw New-Object System.Exception -ArgumentList "Error during installation : $($process.ExitCode)"
            }
            else
            {
                Write-Output "SuccessFull installation"
            }
        }
    }
}


